import java.awt.Color;
import java.awt.Point;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;

// Implementer FTRAIT

public class AffichageGraphique {
	
	static Execution exec;
	static Console console;
	
	public HashMap<String,Integer> argFctPredefinie = new HashMap<String,Integer>();
	public HashMap<String,Method> methodFctPredefinie = new HashMap<String,Method>();
	
	
	public AffichageGraphique(Execution exec,Console console) {
		AffichageGraphique.exec		=	exec;
		AffichageGraphique.console	=	console;		
		
		argFctPredefinie.put("avance", 1);
		argFctPredefinie.put("av", 1);
		argFctPredefinie.put("recule", 1);
		argFctPredefinie.put("re", 1);
		argFctPredefinie.put("tournedroite", 1);
		argFctPredefinie.put("dr", 1);
		argFctPredefinie.put("tournegauche", 1);
		argFctPredefinie.put("ga", 1);
		argFctPredefinie.put("point", 2);
		argFctPredefinie.put("nettoie", 0);
		argFctPredefinie.put("levecrayon", 0);
		argFctPredefinie.put("lc", 0);
		argFctPredefinie.put("baissecrayon", 0);
		argFctPredefinie.put("bc", 0);
		argFctPredefinie.put("fixepos", 2);
		argFctPredefinie.put("fpos", 2);
		argFctPredefinie.put("fixecap", 1);
		argFctPredefinie.put("fcap", 1);
		argFctPredefinie.put("cap", 0);
		argFctPredefinie.put("fcc", 1);
		argFctPredefinie.put("cc", 0);
		argFctPredefinie.put("fcfg", 1);
		argFctPredefinie.put("fixeepais", 1);
		argFctPredefinie.put("fepais", 1);
		argFctPredefinie.put("epais", 0);
		argFctPredefinie.put("montretortue", 0);
		argFctPredefinie.put("cachetortue", 0);
		argFctPredefinie.put("vitesse", 1);
		argFctPredefinie.put("stop", 0);
		argFctPredefinie.put("pause", 0);
		argFctPredefinie.put("finpause", 0);
		
		Class c = AffichageGraphique.class;
		Method[] tab = c.getMethods();
		
		
		Method  m;
		for (int i=0;i<tab.length;i++) {
			m = tab[i];
			if(m.getName().equals("avance")){
				methodFctPredefinie.put("avance", m);
				methodFctPredefinie.put("av", m);
			}
			if(m.getName().equals("recule")){
				methodFctPredefinie.put("recule", m);
				methodFctPredefinie.put("re", m);
			}
			if(m.getName().equals("tournedroite")){
				methodFctPredefinie.put("tournedroite", m);
				methodFctPredefinie.put("dr", m);
			}
			if(m.getName().equals("tournegauche")){
				methodFctPredefinie.put("tournegauche", m);
				methodFctPredefinie.put("ga", m);
			}
			if(m.getName().equals("point")){
				methodFctPredefinie.put("point", m);
			}
			if(m.getName().equals("nettoie")){
				methodFctPredefinie.put("nettoie", m);
			}
			if(m.getName().equals("levecrayon")){
				methodFctPredefinie.put("levecrayon", m);
				methodFctPredefinie.put("lc", m);
			}
			if(m.getName().equals("baissecrayon")){
				methodFctPredefinie.put("baissecrayon", m);
				methodFctPredefinie.put("bc", m);
			}
			if(m.getName().equals("fixepos")){
				methodFctPredefinie.put("fixepos", m);
				methodFctPredefinie.put("fpos", m);
			}
			if(m.getName().equals("fixecap")){
				methodFctPredefinie.put("fixecap", m);
				methodFctPredefinie.put("fcap", m);
			}
			if(m.getName().equals("cap")){
				methodFctPredefinie.put("cap", m);
			}
			if(m.getName().equals("fcc")){
				methodFctPredefinie.put("fcc", m);
			}
			if(m.getName().equals("cc")){
				methodFctPredefinie.put("cc", m);
			}
			if(m.getName().equals("fcfg")){
				methodFctPredefinie.put("fcfg", m);
			}
			if(m.getName().equals("fixeepais")){
				methodFctPredefinie.put("fixeepais", m);
				methodFctPredefinie.put("fepais", m);
			}
			if(m.getName().equals("epais")){
				methodFctPredefinie.put("epais", m);
			}
			if(m.getName().equals("montretortue")){
				methodFctPredefinie.put("montretortue", m);
			}
			if(m.getName().equals("cachetortue")){
				methodFctPredefinie.put("cachetortue", m);
			}
			if(m.getName().equals("vitesse")){
				methodFctPredefinie.put("vitesse", m);
			}
			if(m.getName().equals("stop")){
				methodFctPredefinie.put("stop", m);
			}
			if(m.getName().equals("pause")){
				methodFctPredefinie.put("pause", m);
			}
			if(m.getName().equals("finpause")){
				methodFctPredefinie.put("finpause", m);
			}
		}    
	}


	//Syntaxe  : avance x ou av x
	public static Object avance(ArrayList<Object> v,  HashMap<String, Object> penv) throws ParseException, Exception{
		if(v.size()==1) {
			if ((v.get(0) instanceof Integer))
				{
					exec.Avance((Integer)v.get(0));
					return true;
				}
			else if ((v.get(0) instanceof Double))
			{
				exec.Avance((Integer)v.get(0));
				return true;
			}
			else
				console.err("ERREUR : Type d'argument incorrecte - " + (String) v.get(0));
			return null;
		}
		else {
			console.err("ERREUR : Nombre d'argument incorrecte - " + (String) v.get(0));
			return null;
		}
	}

	//Syntaxe  : recule x ou re x
	public static Object recule(ArrayList<Object> v,  HashMap<String, Object> penv) throws ParseException, Exception{
		if(v.size()==1) {
			if ((v.get(0) instanceof Integer))
			{				
				exec.Recule((Integer)v.get(0));
				return true;
			}
			else if ((v.get(0) instanceof Double))
			{
				exec.Recule((Integer)v.get(0));
				return true;
			}
			else
				console.err("ERREUR : Type d'argument incorrecte - " +(String) v.get(0));
			return null;
		}
		else {
			console.err("ERREUR : Nombre d'argument incorrecte - " +(String) v.get(0));
			return null;
		}
	}
	
	//Syntaxe  : tournedroite x ou dr x
	public static Object tournedroite(ArrayList<Object> v,  HashMap<String, Object> penv) throws ParseException, Exception{		
		if(v.size()==1) {
			if ((v.get(0) instanceof Integer))
			{
					double modifier;					
					if (exec.enDeplacement())
					{
						MessagePile mess = new MessagePile("DI",(Integer)v.get(0));
						exec.getPileDeplacement().add(mess);
					}
					else {
						modifier = exec.getOrientation();
						double angle = java.lang.Math.toRadians((Integer)v.get(0)) + modifier;
						exec.setOrientation(angle%(java.lang.Math.PI*2));
						exec.setTortue(exec.getPoint(),exec.getOrientation(),exec.getAffiche());
					}
					return true;
			}
			else if ((v.get(0) instanceof Double))
			{
					double modifier;					
					if (exec.enDeplacement())
					{
						MessagePile mess = new MessagePile("DD",(Double)v.get(0));
						exec.getPileDeplacement().add(mess);
					}
					else {
						modifier = exec.getOrientation();
						double angle = java.lang.Math.toRadians((Double)v.get(0)) + modifier;
						exec.setOrientation(angle%(java.lang.Math.PI*2));
						exec.setTortue(exec.getPoint(),exec.getOrientation(),exec.getAffiche());
					}
					return true;
			}
			else
				console.err("ERREUR : Type d'argument incorrecte - " + (String) v.get(0));
			return null;
		}
		else {
			console.err("ERREUR : Nombre d'argument incorrecte - " + (String) v.get(0));
			return null;
		}
	}
	
	//Syntaxe  : tournegauche x ou ga x
	public static Object tournegauche(ArrayList<Object> v,  HashMap<String, Object> penv) throws ParseException, Exception{		
		if(v.size()==1) {
			if ((v.get(0) instanceof Integer))
				{
				double modifier;				
				if (exec.enDeplacement())
				{
					MessagePile mess = new MessagePile("GI",(Integer)v.get(0));
					exec.getPileDeplacement().add(mess);
				}
				else {
					modifier = exec.getOrientation();
					double angle = modifier - java.lang.Math.toRadians((Integer)v.get(0));
					exec.setOrientation(angle%(java.lang.Math.PI*2));
					exec.setTortue(exec.getPoint(),exec.getOrientation(),exec.getAffiche());
				}
				return true;
			}
			else if ((v.get(0) instanceof Double))
				{
				double modifier;				
				if (exec.enDeplacement())
				{
					MessagePile mess = new MessagePile("GD",(Double)v.get(0));
					exec.getPileDeplacement().add(mess);
				}
				else {
					modifier = exec.getOrientation();
					double angle = modifier - java.lang.Math.toRadians((Double)v.get(0));
					exec.setOrientation(angle%(java.lang.Math.PI*2));
					exec.setTortue(exec.getPoint(),exec.getOrientation(),exec.getAffiche());
				}
				return true;
			}
			else
				console.err("ERREUR : Type d'argument incorrecte - " + (String) v.get(0));
			return null;
		}
		else {
			console.err("ERREUR : Nombre d'argument incorrecte - " + (String) v.get(0));
			return null;
		}
	}
	
	//Syntaxe  : point [x y]
	public static Object point(ArrayList<Object> v,  HashMap<String, Object> penv) throws ParseException, Exception{		
		if(v.size()==2) {
			if ((v.get(0) instanceof Integer) && (v.get(1) instanceof Integer))	
				{					
					Point p1;
					double orientation;
					float epaisseur;
					Color couleur;
					if (exec.enDeplacement())
					{							
						int [] coordonne = new int[2];
						coordonne[0]=(Integer)v.get(0);
						coordonne[1]=(Integer)v.get(1);
						MessagePile mess = new MessagePile("P",coordonne);
						exec.getPileDeplacement().add(mess);
					}
					else {						
						epaisseur = exec.getEpaisseur();
						couleur = exec.getCouleur();
						orientation = exec.getOrientation();
						p1 = new Point((Integer)(v.get(0)),(Integer)(v.get(1)));
						if (exec.getDessine())
						{
							exec.ajouterDessinable(new point(p1,couleur,epaisseur));						
							exec.repaint();
						}
						exec.setPoint(p1);
						exec.setTortue(p1,orientation,exec.getAffiche());
						exec.setPpx((Integer)v.get(0));
						exec.setPpy((Integer)v.get(1));
					}								
					return true;						
				}
			else if ((v.get(0) instanceof Double) && (v.get(1) instanceof Double))	
			{
				//ERREUR DOUBLE -> INTEGER
				Point p1;
				double orientation;
				float epaisseur;
				Color couleur;
					if (exec.getDessine())
					{
						if (exec.enDeplacement())
						{							
							double [] coordonne = new double[2];
							coordonne[0] = (Double)v.get(0);
							coordonne[1] = (Double)v.get(1);
							MessagePile mess = new MessagePile("PD",coordonne);
							exec.getPileDeplacement().add(mess);
						}
						else {
							epaisseur = exec.getEpaisseur();
							couleur = exec.getCouleur();
							orientation = exec.getOrientation();
							p1 = new Point((Integer)(v.get(0)),(Integer)(v.get(1)));
							exec.ajouterDessinable(new point(p1,couleur,epaisseur));
							exec.repaint();
							exec.setPoint(p1);
							exec.setTortue(p1,orientation,exec.getAffiche());
							exec.setPpx((Double)v.get(0));
							exec.setPpy((Double)v.get(1));
						}
						return true;
					}
					else
					{						
						console.sys("NOTE : Le crayon est leve, aucun point ne sera dessine");
						p1 = new Point((Integer)(v.get(0)),(Integer)(v.get(1)));
						orientation = exec.getOrientation();
						exec.setPoint(p1);
						exec.setTortue(p1,orientation,exec.getAffiche());
						exec.setPpx((Integer)v.get(0));
						exec.setPpy((Integer)v.get(1));
						return true;
					}
			}
			else
				console.err("ERREUR : Type d'argument incorrecte - " +(String) v.get(0));
			return null;
		}
		else {
			console.err("ERREUR : Nombre d'argument incorrecte - " +(String) v.get(0));
			return null;
		}
	}
	
	//Syntaxe : nettoie
	public static Object nettoie(ArrayList<Object> v,  HashMap<String, Object> penv) throws ParseException, Exception{		
		if(v.size()==0) {
			if (exec.enDeplacement())
			{							
				MessagePile mess = new MessagePile("N",null);
				exec.getPileDeplacement().add(mess);
			}
			else
			{
				exec.clearScreen();
				exec.repaint();
			}			
		}
		else
				console.err((String) v.get(0));
			return true;
	}

	//Syntaxe : levecrayon ou lc
	public static Object levecrayon(ArrayList<Object> v,  HashMap<String, Object> penv) throws ParseException, Exception{		
		if(v.size()==0) {
			if (exec.enDeplacement())
			{							
				MessagePile mess = new MessagePile("LC",null);
				exec.getPileDeplacement().add(mess);
			}
			else
			{
				exec.setDessine(false);
			}
		}
		else
				console.err((String) v.get(0));
			return true;
	}
	
	//Syntaxe : baissecrayon ou bc
	public static Object baissecrayon(ArrayList<Object> v,  HashMap<String, Object> penv) throws ParseException, Exception{		
		if(v.size()==0) {
			if (exec.enDeplacement())
			{							
				MessagePile mess = new MessagePile("BC",null);
				exec.getPileDeplacement().add(mess);
			}
			else
			{
				exec.setDessine(true);
			}
		}
		else
				console.err((String) v.get(0));
			return true;
	}
	
	//Syntaxe  : fixepos ou fpos [x y]
	public static Object fixepos(ArrayList<Object> v,  HashMap<String, Object> penv) throws ParseException, Exception{		
		if(v.size()==2) {
			if ((v.get(0) instanceof Integer) && (v.get(1) instanceof Integer))	
				{
					if (exec.enDeplacement())
					{
						int [] coordonne = new int[2];
						coordonne[0]=(Integer)v.get(0);
						coordonne[1]=(Integer)v.get(1);
						MessagePile mess = new MessagePile("FP",coordonne);
						exec.getPileDeplacement().add(mess);
					}
					else {
						Point p1;
						double orientation;
						orientation = exec.getOrientation();
						p1 = new Point((Integer)(v.get(0)),(Integer)(v.get(1)));
						exec.repaint();
						exec.setPoint(p1);
						exec.setTortue(p1,orientation,exec.getAffiche());
						exec.setPpx((Double)v.get(0));
						exec.setPpy((Double)v.get(1));
					}
					return true;
				}
			else if ((v.get(0) instanceof Double) && (v.get(1) instanceof Double))	
			{
//				ERREUR DOUBLE -> INTEGER
				Point p1;
				double orientation;
				orientation = exec.getOrientation();
				p1 = new Point((Integer)(v.get(0)),(Integer)(v.get(1)));
				exec.repaint();
				exec.setPoint(p1);
				exec.setTortue(p1,orientation,exec.getAffiche());
				return true;
			}
			else
				console.err("ERREUR : Type d'argument incorrecte - " +(String) v.get(0));
			return null;
		}
		else {
			console.err("ERREUR : Nombre d'argument incorrecte - " +(String) v.get(0));
			return null;
		}
	}
	
	//Syntaxe  : fixecap ou fcap x
	//Note : x compris entre 0 et 360
	public static Object fixecap(ArrayList<Object> v,  HashMap<String, Object> penv) throws ParseException, Exception{
		if(v.size()==1) {
			if ((v.get(0) instanceof Integer))
			{
				if (exec.enDeplacement())
				{
					MessagePile mess = new MessagePile("FCI",(Integer)v.get(0));
					exec.getPileDeplacement().add(mess);
				}
				else {
					double angle = java.lang.Math.toRadians((Integer)v.get(0));
					exec.setOrientation(angle);
					exec.setTortue(exec.getPoint(),exec.getOrientation(),exec.getAffiche());
				}
				return true;
			}
			else if ((v.get(0) instanceof Double))
			{
				if (exec.enDeplacement())
				{
					MessagePile mess = new MessagePile("FCD",(Double)v.get(0));
					exec.getPileDeplacement().add(mess);
				}
				else {
					double angle = java.lang.Math.toRadians((Double)v.get(0));
					exec.setOrientation(angle);
					exec.setTortue(exec.getPoint(),exec.getOrientation(),exec.getAffiche());
				}
				return true;
			}
			else
				console.err("ERREUR : Type d'argument incorrecte - " +(String) v.get(0));
			return null;
		}
		else {
			console.err("ERREUR : Nombre d'argument incorrecte - " +(String) v.get(0));
			return null;
		}
	}

	//Syntaxe : cap
	public static Object cap(ArrayList<Object> v,  HashMap<String, Object> penv) throws ParseException, Exception{		
		if(v.size()==0) {
			double cap = exec.getOrientation();
			double angle = cap * 2.0 * java.lang.Math.PI / 360.0;
			console.out("Angle en degres : "+cap);
			console.out("Angle en radians: "+angle);
		}
		else
				console.err((String) v.get(0));
			return true;
	}

	//Syntaxe : fcc x
	//Note : x compris entre 0 et 15
	public static Object fcc(ArrayList<Object> v,  HashMap<String, Object> penv) throws ParseException, Exception{
		if(v.size()==1) {
			if (((v.get(0) instanceof Integer)||(v.get(0) instanceof Double)))
			{
				Color cc ;
				switch ((Integer)v.get(0))
				{
				case 0: cc=(Color.BLACK);	break;
				case 1: cc=(Color.BLUE); 	break;
				case 3: cc=(Color.PINK);	break;
				case 4: cc=(Color.RED);		break;
				case 5: cc=(Color.MAGENTA); break;
				case 6: cc=(Color.ORANGE);	break;
				case 7: cc=(Color.LIGHT_GRAY);	break;
				case 8: cc=(Color.DARK_GRAY);	break;
				case 9: cc=(Color.blue);	break;
				case 10:cc=(Color.green);	break;
				case 11:cc=(Color.pink);	break;
				case 12:cc=(Color.red);	break;
				case 13:cc=(Color.magenta);	break;
				case 14:cc=(Color.YELLOW);	break;
				case 15:cc=(Color.WHITE);	break;
				default:
					cc=(Color.BLACK);
					break;
				}
				if(exec.enDeplacement())
				{
					MessagePile mess = new MessagePile("FCC",(Color)cc);
					exec.getPileDeplacement().add(mess);
				}
				else {exec.setCouleur(cc);}
				return true;
			}
			else
				console.err("ERREUR : Type d'argument incorrecte - " +(String) v.get(0));
			return null;
		}
		else {
			console.err("ERREUR : Nombre d'argument incorrecte - " +(String) v.get(0));
			return null;
		}
	}
	
	//	Syntaxe : cc
	public static Object cc(ArrayList<Object> v,  HashMap<String, Object> penv) throws ParseException, Exception{		
		if(v.size()==0) 
		{
			console.out("NOTE : Couleur actuel du crayon : "+exec.getCouleur());
		}
		else
		{
			console.err("ERREUR : Nombre d'argument incorrecte - " +(String) v.get(0));
			return null;
		}
		return true;
	}
	
	//Syntaxe : fcfg x
	//Note : x compris entre 0 et 15
	public static Object fcfg(ArrayList<Object> v,  HashMap<String, Object> penv) throws ParseException, Exception{
		if(v.size()==1) {
			if (((v.get(0) instanceof Integer)||(v.get(0) instanceof Double)))
			{
				Color cc;
				switch ((Integer)v.get(0))
				{
				case 0: cc=(Color.WHITE);	break;
				case 1: cc=(Color.BLUE); 	break;
				case 3: cc=(Color.PINK);	break;
				case 4: cc=(Color.RED);		break;
				case 5: cc=(Color.MAGENTA); break;
				case 6: cc=(Color.ORANGE);	break;
				case 7: cc=(Color.LIGHT_GRAY);	break;
				case 8: cc=(Color.DARK_GRAY);	break;
				case 9: cc=(Color.blue);	break;
				case 10:cc=(Color.green);	break;
				case 11:cc=(Color.pink);	break;
				case 12:cc=(Color.red);	break;
				case 13:cc=(Color.magenta);	break;
				case 14:cc=(Color.YELLOW);	break;
				case 15:cc=(Color.BLACK);	break;
				default:cc=(Color.WHITE);	break;
				}
				if(exec.enDeplacement())
				{
					MessagePile mess = new MessagePile("FCFG",(Color)cc);
					exec.getPileDeplacement().add(mess);
				}
				else {exec.setFond(cc);}
				return true; 
			}
			else
				console.err("ERREUR : Type d'argument incorrecte - " +(String) v.get(0));
			return null;
		}
		else {
			console.err("ERREUR : Nombre d'argument incorrecte - " +(String) v.get(0));
			return null;
		}
	}

	//Syntaxe : cf
	public static Object cf(ArrayList<Object> v,  HashMap<String, Object> penv) throws ParseException, Exception{		
		if(v.size()==0) 
		{
			console.out("NOTE : Couleur actuel du fond : "+exec.getFond());
		}
		else
		{
			console.err("ERREUR : Nombre d'argument incorrecte - " +(String) v.get(0));
			return null;
		}
		return true;
	}

	//Syntaxe  : fixepais ou fepais x
	public static Object fixeepais(ArrayList<Object> v,  HashMap<String, Object> penv) throws ParseException, Exception{
		if(v.size()==1) {
			if ((v.get(0) instanceof Integer)||(v.get(0) instanceof Double)||(v.get(0) instanceof Float))
			{
				if(exec.enDeplacement())
				{
					MessagePile mess = new MessagePile("E",(Integer)v.get(0));
					exec.getPileDeplacement().add(mess);
				}
				else {
					int epaisseur = (Integer)v.get(0);
					exec.setEpaisseur(epaisseur);
				}				
				return true;
			}
			else
				console.err("ERREUR : Type d'argument incorrecte - " +(String) v.get(0));
			return null;
		}
		else {
			console.err("ERREUR : Nombre d'argument incorrecte - " +(String) v.get(0));
			return null;
		}
	}
	
	//	Syntaxe : epais
	public static Object epais(ArrayList<Object> v,  HashMap<String, Object> penv) throws ParseException, Exception{		
		if(v.size()==0) 
		{
			console.out("NOTE : Epaisseur actuel du crayon : "+exec.getEpaisseur());
		}
		else
		{
			console.err("ERREUR : Nombre d'argument incorrecte - " +(String) v.get(0));
			return null;
		}
		return true;
	}
	
	//	Syntaxe : montretortue
	public static Object montretortue(ArrayList<Object> v,  HashMap<String, Object> penv) throws ParseException, Exception{		
		if(v.size()==0) {
			exec.setAffiche(true);
			exec.setTortue(exec.getPoint(),exec.getOrientation(),true);
		}
		else
				console.err((String) v.get(0));
		return true;
	}
	
	//	Syntaxe : cachetortue
	public static Object cachetortue(ArrayList<Object> v,  HashMap<String, Object> penv) throws ParseException, Exception{		
		if(v.size()==0) {
			exec.setAffiche(false);
			exec.setTortue(exec.getPoint(),exec.getOrientation(),false);
		}
		else
				console.err((String) v.get(0));
		return true;
	}
	
//	Syntaxe : vitesse 1
	public static Object vitesse(ArrayList<Object> v,  HashMap<String, Object> penv) throws ParseException, Exception{		
		if(v.size()==1) {
			if ((v.get(0) instanceof Integer))
				if ((Integer) v.get(0)>=1 && (Integer) v.get(0)<=500)
					exec.setVitesse((Integer) v.get(0));
				else console.err("ERREUR : La vitesse doit etre comprise entre 1 et 500, vous avez choisi : " + v.get(0));
			else console.err("ERREUR : Type d'argument incorrecte - " +(String) v.get(0));
		}
		else console.err((String) v.get(0));
		return true;
	}
	
	public static Object stop(ArrayList<Object> v,  HashMap<String, Object> penv) throws ParseException, Exception{		
		if(v.size()==0) {
			exec.StopDeplacement();
		}
		else return null;
		return true;
	}
	
	public static Object pause(ArrayList<Object> v,  HashMap<String, Object> penv) throws ParseException, Exception{		
		if(v.size()==0) {
			exec.PauseDeplacement();
		}
		else return null;
		return true;
	}
	
	public static Object finpause(ArrayList<Object> v,  HashMap<String, Object> penv) throws ParseException, Exception{		
		if(v.size()==0) {
			exec.FinPauseDeplacement();
		}
		else return null;
		return true;
	}
	
	
	
}


